#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>

// 手动定义I2C相关的结构体和常量，避免交叉编译环境下的头文件问题
#ifndef I2C_M_RD
#define I2C_M_RD 0x0001
#endif

#ifndef I2C_SLAVE
#define I2C_SLAVE 0x0703
#endif

#ifndef I2C_RDWR
#define I2C_RDWR 0x0707
#endif

struct i2c_msg {
    unsigned short addr;
    unsigned short flags;
    unsigned short len;
    unsigned char *buf;
};

struct i2c_rdwr_ioctl_data {
    struct i2c_msg *msgs;
    unsigned int nmsgs;
};

// I2C设备路径
#define I2C_DEVICE "/dev/i2c-4"
#define I2C_ADDR 0x30

// 函数声明
int i2c_read_register(int fd, unsigned char reg_addr, unsigned char *data);
int i2c_write_register(int fd, unsigned char reg_addr, unsigned char value);
void print_usage(const char *program_name);

int main(int argc, char **argv)
{
    int fd;
    int ret;
    unsigned char reg_addr, reg_value;
    
    if (argc < 2) {
        print_usage(argv[0]);
        return 1;
    }
    
    // 打开I2C设备
    fd = open(I2C_DEVICE, O_RDWR);
    if (fd < 0) {
        perror("打开I2C设备失败");
        return -1;
    }
    
    printf("成功打开I2C设备: %s\n", I2C_DEVICE);
    printf("设置I2C从设备地址: 0x%02X\n", I2C_ADDR);
    
    // 注意：在使用I2C_RDWR ioctl时，不需要预先设置I2C_SLAVE
    // 地址在每个消息中单独指定
    printf("I2C设备准备就绪，将在ioctl中指定设备地址\n");
    
    if (strcmp(argv[1], "read") == 0) {
        // 读寄存器命令: read <寄存器地址>
        if (argc != 3) {
            printf("读寄存器用法: %s read <寄存器地址>\n", argv[0]);
            printf("示例: %s read 0x22\n", argv[0]);
            close(fd);
            return 1;
        }
        
        reg_addr = strtol(argv[2], NULL, 16);
        printf("读取寄存器 0x%02X 的值...\n", reg_addr);
        
        ret = i2c_read_register(fd, reg_addr, &reg_value);
        if (ret == 0) {
            printf("寄存器 0x%02X 的值: 0x%02X\n", reg_addr, reg_value);
        } else {
            printf("读取寄存器失败\n");
        }
        
    } else if (strcmp(argv[1], "write") == 0) {
        // 写寄存器命令: write <寄存器地址> <值>
        if (argc != 4) {
            printf("写寄存器用法: %s write <寄存器地址> <值>\n", argv[0]);
            printf("示例: %s write 0x22 0x02\n", argv[0]);
            close(fd);
            return 1;
        }
        
        reg_addr = strtol(argv[2], NULL, 16);
        reg_value = strtol(argv[3], NULL, 16);
        printf("写入寄存器 0x%02X 值: 0x%02X\n", reg_addr, reg_value);
        
        ret = i2c_write_register(fd, reg_addr, reg_value);
        if (ret == 0) {
            printf("写入寄存器成功\n");
        } else {
            printf("写入寄存器失败\n");
        }
        
    } else if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
        print_usage(argv[0]);
    } else {
        printf("未知命令: %s\n", argv[1]);
        print_usage(argv[0]);
        close(fd);
        return 1;
    }
    
    close(fd);
    return 0;
}

// 读寄存器函数 - 模拟i2ctransfer的方式
int i2c_read_register(int fd, unsigned char reg_addr, unsigned char *data)
{
    struct i2c_msg msgs[2];
    struct i2c_rdwr_ioctl_data msgset;
    unsigned char write_buf[2];
    
    // 准备写入数据：0x32 + 寄存器地址
    write_buf[0] = 0x32;  // 地址前缀
    write_buf[1] = reg_addr;  // 寄存器地址
    
    // 写寄存器地址 (w2@0x30 0x32 0x22)
    msgs[0].addr = 0x30;  // 使用原始地址格式
    msgs[0].flags = 0; // 写操作
    msgs[0].len = 2;
    msgs[0].buf = write_buf;
    
    // 读数据 (r1@0x30)
    msgs[1].addr = 0x30;  // 使用原始地址格式
    msgs[1].flags = I2C_M_RD; // 读操作
    msgs[1].len = 1;
    msgs[1].buf = data;
    
    msgset.msgs = msgs;
    msgset.nmsgs = 2;
    
    printf("调试: 写入地址前缀=0x%02X, 寄存器地址=0x%02X\n", write_buf[0], write_buf[1]);
    
    if (ioctl(fd, I2C_RDWR, &msgset) < 0) {
        perror("I2C读操作失败");
        printf("错误详情: %s\n", strerror(errno));
        return -1;
    }
    
    return 0;
}

// 写寄存器函数 - 模拟i2ctransfer的方式
int i2c_write_register(int fd, unsigned char reg_addr, unsigned char value)
{
    struct i2c_msg msg;
    struct i2c_rdwr_ioctl_data msgset;
    unsigned char buf[3];
    
    // 准备数据: 0x32 + 寄存器地址 + 值 (w3@0x30 0x32 0x22 0x02)
    buf[0] = 0x32;      // 地址前缀
    buf[1] = reg_addr;  // 寄存器地址
    buf[2] = value;     // 寄存器值
    
    msg.addr = 0x30;  // 使用原始地址格式
    msg.flags = 0; // 写操作
    msg.len = 3;
    msg.buf = buf;
    
    msgset.msgs = &msg;
    msgset.nmsgs = 1;
    
    printf("调试: 写入地址前缀=0x%02X, 寄存器地址=0x%02X, 值=0x%02X\n", buf[0], buf[1], buf[2]);
    
    if (ioctl(fd, I2C_RDWR, &msgset) < 0) {
        perror("I2C写操作失败");
        printf("错误详情: %s\n", strerror(errno));
        return -1;
    }
    
    return 0;
}

// 显示使用帮助
void print_usage(const char *program_name)
{
    printf("I2C寄存器读写工具\n");
    printf("用法: %s <命令> [参数]\n\n", program_name);
    printf("命令:\n");
    printf("  read <寄存器地址>    读取指定寄存器的值\n");
    printf("  write <寄存器地址> <值>  向指定寄存器写入值\n");
    printf("  -h, --help          显示此帮助信息\n\n");
    printf("示例:\n");
    printf("  %s read 0x22        读取寄存器0x22的值\n", program_name);
    printf("  %s write 0x22 0x02  向寄存器0x22写入值0x02\n", program_name);
    printf("\n注意: 需要root权限运行，设备地址固定为0x30，I2C总线为/dev/i2c-4\n");
}
